package io.netty.util.concurrent;

import io.netty.util.internal.InternalThreadLocalMap;
import io.netty.util.internal.PlatformDependent;

import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Set;
import java.util.UUID;

public class FastThreadLocal<V> {

    //InternalThreadLocalMap对象数组里面的一个索引下标，这个下标是位置为0的下标，表示的是待删除的FastThreadLocal。
    private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();
    //表示当前FastThreadLocal对象对应的value值存储在InternalThreadLocalMap对象数组的哪个索引下
    private final int index;

    //注意：多线程是共享同一个FastThreadLocal对象的
    public FastThreadLocal() {
        //这个和FastThreadLocal对象的创建有关
        //假设是第一次创建 ， index =1
        //第二次创建 ， index =2 。
        //。。。。。以此类推
        index = InternalThreadLocalMap.nextVariableIndex();
    }


    //清除掉所有资源
    public static void removeAll() {
        //拿到线程A对应的InternalThreadLocalMap对象
        InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
        //如果为空，说明根本初始化过，或者已经被释放了，直接返回即可。
        if (threadLocalMap == null) {
            return;
        }

        try {
            //获取到InternalThreadLocalMap里面的对象数组里面的待删除的FastThreadLocal对象
            Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
            //对象数组已经初始化过
            if (v != null && v != InternalThreadLocalMap.UNSET) {
                @SuppressWarnings("unchecked")
                //获取到待删除列表
                Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;
                //转化成数组
                FastThreadLocal<?>[] variablesToRemoveArray =
                        variablesToRemove.toArray(new FastThreadLocal[0]);
                //遍历数组
                for (FastThreadLocal<?> tlv: variablesToRemoveArray) {
                    //清理
                    tlv.remove(threadLocalMap);
                }
            }
        } finally {
            //清理掉线程A对应的InternalThreadLocalMap对象。
            InternalThreadLocalMap.remove();
        }
    }

    public static int size() {
        InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
        if (threadLocalMap == null) {
            return 0;
        } else {
            return threadLocalMap.size();
        }
    }

    public static void destroy() {
        InternalThreadLocalMap.destroy();
    }

    //将当前对象放入到线程A的InternalThreadLocalMap的待删除集合中。
    @SuppressWarnings("unchecked")
    private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap/*线程A的InternalThreadLocalMap对象*/,
                                               FastThreadLocal<?> variable/*当前对象*/) {
        //去线程A的InternalThreadLocalMap对象里面拿线程A的待删除集合
        Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
        //待删除集合的引用
        Set<FastThreadLocal<?>> variablesToRemove;
        //条件成立：线程A没有待删除集合
        if (v == InternalThreadLocalMap.UNSET || v == null) {
            //创建一个待删除集合
            variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<FastThreadLocal<?>, Boolean>());
            //设置到线程A的InternalThreadLocalMap里面
            threadLocalMap.setIndexedVariable(variablesToRemoveIndex, variablesToRemove);
        } else {
            //条件成立：线程A已经设置过待删除集合
            //此时，直接引用赋值即可。
            variablesToRemove = (Set<FastThreadLocal<?>>) v;
        }
        //将当前对象加入到线程A的待删除集合中...
        variablesToRemove.add(variable);
    }

    //从线程A对应的InternalThreadLocalMap对应的对象数组的删除集合里面移除掉当前FastThreadLocal对象
    private static void removeFromVariablesToRemove(
            InternalThreadLocalMap threadLocalMap/*线程A的InternalThreadLocalMap对象*/,
            FastThreadLocal<?> variable/*当前对象*/) {
        //获取到线程A对应的InternalThreadLocalMap对应的对象数组的删除集合
        Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
        //删除集合未初始化，直接返回即可
        if (v == InternalThreadLocalMap.UNSET || v == null) {
            return;
        }

        @SuppressWarnings("unchecked")
        Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;
        //从删除集合里面移除
        variablesToRemove.remove(variable);
    }





    @SuppressWarnings("unchecked")
    public final V get() {
        //拿到线程A对应的InternalThreadLocalMap对象
        InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
        //拿到线程A对应的InternalThreadLocalMap对象使用当前FastThreadLocal对象存储的value
        Object v = threadLocalMap.indexedVariable(index);
        //说明set过
        if (v != InternalThreadLocalMap.UNSET) {
            //直接返回结果
            return (V) v;
        }
        //走到这里，说明没set过。
        //走初始化的逻辑...
        return initialize(threadLocalMap);
    }

    @SuppressWarnings("unchecked")
    public final V getIfExists() {
        InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
        if (threadLocalMap != null) {
            Object v = threadLocalMap.indexedVariable(index);
            if (v != InternalThreadLocalMap.UNSET) {
                return (V) v;
            }
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    public final V get(InternalThreadLocalMap threadLocalMap) {
        Object v = threadLocalMap.indexedVariable(index);
        if (v != InternalThreadLocalMap.UNSET) {
            return (V) v;
        }

        return initialize(threadLocalMap);
    }

    //初始化的逻辑
    private V initialize(InternalThreadLocalMap threadLocalMap) {
        //声明一个值
        V v = null;
        try {
            //这里默认返回空，如果有需要，可以重写该方法
            v = initialValue();
        } catch (Exception e) {
            PlatformDependent.throwException(e);
        }
        //设置到线程A对应的InternalThreadLocalMap对象的对象数组里面
        threadLocalMap.setIndexedVariable(index, v);
        //将当前FastThreadLocal对象加入到线程A对应的InternalThreadLocalMap对象的对象数组的待删除列表里面
        addToVariablesToRemove(threadLocalMap, this);
        //默认返回null
        return v;
    }

    //线程A设置一个值
    public final void set(V value) {
        //判断传进来的值是不是unset，如果是unset那就走删除的逻辑
        //否则走正常的逻辑
        if (value != InternalThreadLocalMap.UNSET) {
            //获取线程A对应的InternalThreadLocalMap
            InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
            //将value设置到线程A的InternalThreadLocalMap里面。
            setKnownNotUnset(threadLocalMap, value);
        } else {
            //此时需要删除线程A之前调用当前FastThreadLocal对象set的值
            remove();
        }
    }

    public final void set(InternalThreadLocalMap threadLocalMap, V value) {
        if (value != InternalThreadLocalMap.UNSET) {
            setKnownNotUnset(threadLocalMap, value);
        } else {
            remove(threadLocalMap);
        }
    }

    //将value设置到线程A的InternalThreadLocalMap里面。
    private void setKnownNotUnset(InternalThreadLocalMap threadLocalMap/*线程A的InternalThreadLocalMap*/, V value/*要设置的值*/) {
        //设置值到线程A的InternalThreadLocalMap，如果是替换返回false，如果是初始设置返回true。
        if (threadLocalMap.setIndexedVariable(index, value)) {
            //条件成立：说明是初次设置。
            //这个时候需要将当前的FastThreadLocal对象加入到线程A自己的InternalThreadLocalMap的待删除集合里面，
            //表示线程A使用了这个FastThreadLocal对象，后续需要释放该对象和她对象应的值。
            addToVariablesToRemove(threadLocalMap, this);
        }
    }

    public final boolean isSet() {
        return isSet(InternalThreadLocalMap.getIfSet());
    }

    public final boolean isSet(InternalThreadLocalMap threadLocalMap) {
        return threadLocalMap != null && threadLocalMap.isIndexedVariableSet(index);
    }

    //删除线程A之前调用当前FastThreadLocal对象set的值
    public final void remove() {
        remove(InternalThreadLocalMap.getIfSet()/*拿到线程A对应的InternalThreadLocalMap对象*/);
    }

    @SuppressWarnings("unchecked")
    public final void remove(InternalThreadLocalMap threadLocalMap/*线程A对应的InternalThreadLocalMap对象*/) {
        //条件成立：线程A对应的InternalThreadLocalMap还没初始化，直接返回就行了。
        if (threadLocalMap == null) {
            return;
        }

        //此时一定是初始化过了。
        //这个时候就从map里面移除当前FastThreadLocal对象对应的值。
        Object v = threadLocalMap.removeIndexedVariable(index);
        //同时把当前对象从线程A的map的对象数组的删除集合里面移除掉
        removeFromVariablesToRemove(threadLocalMap, this);
        //这个值不是unset..那就说明线程A调用过当前对象的set方法设置过值
        if (v != InternalThreadLocalMap.UNSET) {
            try {
                //移除的逻辑，留给子类扩展
                onRemoval((V) v);
            } catch (Exception e) {
                PlatformDependent.throwException(e);
            }
        }
    }

    //默认返回null，留给子类重写
    protected V initialValue() throws Exception {
        return null;
    }

    protected void onRemoval(@SuppressWarnings("UnusedParameters") V value) throws Exception { }
}
